package com.anmong.cloud.cloudcommon.exception;


import com.anmong.cloud.cloudcommon.response.R;
import feign.RetryableException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 拦截捕捉自定义异常 CommonException.class
     *给前端返回
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = CommonException.class)
    public R CommonErrorHandler(CommonException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode(String.valueOf(ex.getCode()));
        response.setMessage(ex.getMessage());
        log.error("自定义异常:{}",ex.getMessage(),ex);
        return response;
    }

    /**
     * rpc调用异常
     *给前端返回
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
    @ExceptionHandler(value = ApiInvokeException.class)
    public R ApiInvokeErrorHandler(ApiInvokeException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode(String.valueOf(ex.getCode()));
        response.setMessage("内部服务出错，请稍后再试!");
        log.error("微服务调用异常:{}",ex.getMessage(),ex);
        return response;
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT)
    @ExceptionHandler(value = RetryableException.class)
    public R ApiInvokeErrorHandler(RetryableException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("504");
        response.setMessage("内部服务暂不可用，请稍后再试!");
        log.error("微服务调用超时:{}",ex.getMessage(),ex);
        return response;
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = RpcInternalException.class)
    public R RpcInternalErrorHandler(RpcInternalException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode(String.valueOf(ex.getCode()));
        response.setMessage(ex.getMessage());
        log.error("微服务调用内部出错:{}",ex.getMessage(),ex);
        return response;
    }



    /**
     * 全局异常返回
     *
     * @param ex
     * @return
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public R BasicErrorHandler(Exception ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("500");
        response.setMessage("出错了，请稍后再试!");
        log.error("全局错误:{}",ex.getMessage(),ex);
        return response;
    }

    /**
     * 参数缺少
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public R prametersErrorHandler(MissingServletRequestParameterException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("400");
        response.setMessage("缺少参数:"+ex.getMessage());
        log.error("微服务调用异常:{}",ex.getMessage(),ex);
        return response;
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(value = ForbiddenException.class)
    public R forbiddenErrorHandler(ForbiddenException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode(String.valueOf(ex.getCode()));
        response.setMessage("权限不足:"+ex.getMessage());
        log.error("无权限操作：{}",ex.getMessage(),ex);
        return response;
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(value = UnauthorizedException.class)
    public R unauthorizedErrorHandler(UnauthorizedException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode(String.valueOf(ex.getCode()));
        response.setMessage("认证出错:"+ex.getMessage());
        log.error("认证出错：{}",ex.getMessage(),ex);
        return response;
    }

    /**
     * 处理 form data方式调用接口校验失败抛出的异常
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R prametersErrorHandler(MethodArgumentNotValidException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("400");
        List<FieldError> fieldErrors =  ex.getBindingResult().getFieldErrors();
        List<String> collect = fieldErrors.stream()
                .map(o -> "参数异常字段"+o.getField()+":"+o.getDefaultMessage())
                .collect(Collectors.toList());
        response.setMessage("参数格式错误:"+collect);
        log.error("微服务调用异常:{}",ex.getMessage(),ex);
        return response;
    }

    /**
     * 处理 json 请求体调用接口校验失败抛出的异常
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = BindException.class)
    public R prametersErrorHandler(BindException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("400");
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        List<String> collect = fieldErrors.stream()
                .map(o ->  "参数异常字段"+o.getField()+":"+o.getDefaultMessage())
                .collect(Collectors.toList());
        response.setMessage("参数不能为空:"+collect);
        log.error("微服务调用异常:{}",ex.getMessage(),ex);
        return response;
    }

    /**
     * 处理单个参数校验失败抛出的异常(spring-validation抛出)
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ConstraintViolationException.class)
    public R prametersErrorHandler(ConstraintViolationException ex) {
        R response = new R();
        response.setSuccess(false);
        response.setCode("400");
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        List<String> collect = constraintViolations.stream()
                .map(o -> o.getMessage())
                .collect(Collectors.toList());
        response.setMessage("参数格式错误:"+collect);
        log.error("微服务调用异常:{}",ex.getMessage(),ex);
        return response;
    }









}
